from flask import Flask, render_template, request, jsonify, send_file
import json
import os
from datetime import datetime, timedelta
import uuid
from threading import Timer
import copy

app = Flask(__name__)

# 数据文件路径
DATA_DIR = "data"
CLASSES_FILE = os.path.join(DATA_DIR, "classes.json")
HISTORY_FILE = os.path.join(DATA_DIR, "history.json")
ACTIVE_CLASS_FILE = os.path.join(DATA_DIR, "active_class.json")

# 确保数据目录存在
if not os.path.exists(DATA_DIR):
    os.makedirs(DATA_DIR)

# 初始化数据文件
def init_data_files():
    if not os.path.exists(CLASSES_FILE):
        with open(CLASSES_FILE, 'w', encoding='utf-8') as f:
            json.dump({}, f, ensure_ascii=False, indent=2)
    
    if not os.path.exists(HISTORY_FILE):
        with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
            json.dump([], f, ensure_ascii=False, indent=2)
    
    if not os.path.exists(ACTIVE_CLASS_FILE):
        with open(ACTIVE_CLASS_FILE, 'w', encoding='utf-8') as f:
            json.dump({"active": False, "classId": "", "startTime": "", "duration": 40, "remaining": 40*60}, f, ensure_ascii=False, indent=2)


# 读取班级数据
def load_classes():
    try:
        with open(CLASSES_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except:
        return {}

# 保存班级数据
def save_classes(data):
    with open(CLASSES_FILE, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

# 读取历史记录
def load_history():
    try:
        with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except:
        return []

# 保存历史记录
def save_history(data):
    with open(HISTORY_FILE, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

# 读取活跃班级信息
def load_active_class():
    try:
        with open(ACTIVE_CLASS_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    except:
        return {"active": False, "classId": "", "startTime": "", "duration": 40, "remaining": 40*60}

# 保存活跃班级信息
def save_active_class(data):
    with open(ACTIVE_CLASS_FILE, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

# 检查全勤奖励
def check_attendance_reward(class_id, classes):
    if class_id not in classes:
        return False
        
    class_info = classes[class_id]
    
    # 获取最近4次课的历史记录
    recent_classes = []
    history = load_history()
    
    for record in reversed(history):
        if record.get('classId') == class_id and record.get('type') == 'class_session':
            recent_classes.append(record)
            if len(recent_classes) >= 4:
                break
    
    # 检查最近4次课是否有扣分
    if len(recent_classes) < 4:
        return False
        
    for session in recent_classes:
        if session.get('hadDeduction', False):
            return False
    
    # 检查是否已经奖励过（避免重复奖励）
    last_reward_time = class_info.get('lastAttendanceReward', '')
    if last_reward_time and len(recent_classes) > 0:
        last_session_time = recent_classes[0].get('time', '')
        if last_reward_time >= last_session_time:
            return False
    
    return True

# 主页路由
@app.route('/')
def index():
    return render_template('index.html')

# API路由 - 获取所有数据
@app.route('/api/data', methods=['GET'])
def get_all_data():
    classes = load_classes()
    history = load_history()
    active_class = load_active_class()  # 只包含课堂计时器
    
    # 获取冻结阈值（从第一个班级中获取，如果没有则使用默认值）
    freeze_threshold = 30
    if classes:
        first_class = next(iter(classes.values()))
        freeze_threshold = first_class.get('freeze_threshold', 30)
    
    return jsonify({
        'classData': classes,
        'freezeThreshold': freeze_threshold,
        'recentHistory': history[-100:],  # 只返回最近100条记录
        'activeClass': active_class  # 只包含课堂计时器，不包含奖励计时器
    })

# API路由 - 保存所有数据
@app.route('/api/data', methods=['POST'])
def save_all_data():
    data = request.json
    
    # 更新冻结阈值到所有班级
    freeze_threshold = data.get('freezeThreshold', 30)
    class_data = data.get('classData', {})
    
    for class_id in class_data:
        class_data[class_id]['freeze_threshold'] = freeze_threshold
    
    save_classes(class_data)
    
    # 保存历史记录
    history = data.get('recentHistory', [])
    save_history(history)
    
    return jsonify({'status': 'success'})

# API路由 - 添加班级
@app.route('/api/class', methods=['POST'])
def add_class():
    data = request.json
    class_name = data.get('name', '').strip()
    score = data.get('score', 40)
    
    if not class_name:
        return jsonify({'status': 'error', 'message': '班级名称不能为空'})
    
    classes = load_classes()
    
    # 生成唯一ID
    class_id = f"class_{uuid.uuid4().hex[:8]}"
    
    classes[class_id] = {
        'name': class_name,
        'score': score,
        'initial_score': score,  # 保存初始分数
        'created': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'freeze_threshold': 30,
        'reward_used': 0,  # 已使用的奖励时间
        'penalty_used': 0,  # 已执行的惩罚节数
        'recentSessions': [],  # 最近上课记录
        'lastAttendanceReward': ''  # 上次全勤奖励时间
    }
    
    save_classes(classes)
    
    return jsonify({'status': 'success', 'classId': class_id})



# API路由 - 删除班级
@app.route('/api/class/<class_id>', methods=['DELETE'])
def delete_class(class_id):
    classes = load_classes()
    
    if class_id in classes:
        del classes[class_id]
        save_classes(classes)
        return jsonify({'status': 'success'})
    else:
        return jsonify({'status': 'error', 'message': '班级不存在'})

# API路由 - 记录分数
@app.route('/api/record', methods=['POST'])
def record_score():
    data = request.json
    class_id = data.get('classId')
    points = data.get('points')
    reason = data.get('reason', '')
    
    if not class_id or points is None:
        return jsonify({'status': 'error', 'message': '参数不完整'})
    
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    # 检查是否有活跃课程，如果有，标记该课程有扣分
    active_class = load_active_class()
    if active_class.get('active') and active_class.get('classId') == class_id and points < 0:
        # 标记本次课程有扣分
        history = load_history()
        for record in reversed(history):
            if record.get('classId') == class_id and record.get('type') == 'class_session' and record.get('sessionId') == active_class.get('sessionId'):
                record['hadDeduction'] = True
                save_history(history)
                break
    
    # 更新班级分数，确保在0~100之间
    new_score = classes[class_id]['score'] + points
    if new_score > 100:
        new_score = 100
    elif new_score < 0:
        new_score = 0
    classes[class_id]['score'] = new_score
    save_classes(classes)
    
    # 添加历史记录
    history = load_history()
    record = {
        'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'classId': class_id,
        'className': classes[class_id]['name'],
        'points': points,
        'reason': reason,
        'type': 'manual_record'
    }
    history.append(record)
    save_history(history)
    
    return jsonify({'status': 'success'})

# API路由 - 开始上课
@app.route('/api/start-class', methods=['POST'])
def start_class():
    data = request.json
    class_id = data.get('classId')
    duration = data.get('duration', 40)  # 默认40分钟
    
    if not class_id:
        return jsonify({'status': 'error', 'message': '请选择班级'})
    
    classes = load_classes()
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    active_class = {
        'active': True,
        'classId': class_id,
        'startTime': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'duration': duration,
        'remaining': duration * 60,  # 转换为秒
        'sessionId': str(uuid.uuid4())  # 本次课程唯一ID
    }
    
    save_active_class(active_class)
    
    # 记录课程开始
    history = load_history()
    history.append({
        'time': active_class['startTime'],
        'classId': class_id,
        'className': classes[class_id]['name'],
        'type': 'class_session',
        'sessionId': active_class['sessionId'],
        'hadDeduction': False  # 初始化为无扣分
    })
    save_history(history)
    
    return jsonify({'status': 'success', 'sessionId': active_class['sessionId']})

# API路由 - 结束上课
@app.route('/api/end-class', methods=['POST'])
def end_class():
    active_class = load_active_class()
    
    if not active_class.get('active'):
        return jsonify({'status': 'error', 'message': '没有正在进行的课程'})
    
    class_id = active_class.get('classId')
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    # 检查课程是否有扣分
    history = load_history()
    had_deduction = False
    for record in reversed(history):
        if record.get('classId') == class_id and record.get('type') == 'class_session' and record.get('sessionId') == active_class.get('sessionId'):
            had_deduction = record.get('hadDeduction', False)
            break
    
    # 如果课程无扣分，奖励协作表现分
    if not had_deduction:
        classes[class_id]['score'] += 2  # 协作表现奖励2分
        
        # 记录奖励
        history.append({
            'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'classId': class_id,
            'className': classes[class_id]['name'],
            'points': 2,
            'reason': '协作表现奖励（整节课无违纪）',
            'type': 'auto_reward'
        })
    
    # 检查全勤奖励
    if check_attendance_reward(class_id, classes):
        classes[class_id]['score'] += 3  # 全勤奖励3分
        classes[class_id]['lastAttendanceReward'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        
        # 记录奖励
        history.append({
            'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'classId': class_id,
            'className': classes[class_id]['name'],
            'points': 3,
            'reason': '全勤奖励（最近4次课无违纪）',
            'type': 'auto_reward'
        })
    
    save_classes(classes)
    save_history(history)
    
    # 重置活跃课程状态
    save_active_class({"active": False, "classId": "", "startTime": "", "duration": 40, "remaining": 40*60})
    
    return jsonify({'status': 'success', 'hadDeduction': had_deduction})

# API路由 - 获取自由探索时间
@app.route('/api/free-time/<class_id>', methods=['GET'])
def get_free_time(class_id):
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    score = classes[class_id]['score']
    
    # 计算自由探索时间
    if score >= 90:
        free_time = 15
    elif score >= 80:
        free_time = 10
    elif score >= 70:
        free_time = 8
    elif score >= 60:
        free_time = 5
    else:
        free_time = 0
    
    return jsonify({'status': 'success', 'freeTime': free_time})

# API路由 - 导出数据
@app.route('/api/export', methods=['GET'])
def export_data():
    classes = load_classes()
    history = load_history()
    
    # 获取冻结阈值
    freeze_threshold = 30
    if classes:
        first_class = next(iter(classes.values()))
        freeze_threshold = first_class.get('freeze_threshold', 30)
    
    export_data = {
        'classData': classes,
        'freezeThreshold': freeze_threshold,
        'recentHistory': history,
        'exportTime': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'version': '2.0'
    }
    
    # 创建临时文件
    filename = f"classroom_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
    temp_path = os.path.join(DATA_DIR, filename)
    
    with open(temp_path, 'w', encoding='utf-8') as f:
        json.dump(export_data, f, ensure_ascii=False, indent=2)
    
    return send_file(temp_path, as_attachment=True, download_name=filename)

# 核销奖励
@app.route('/api/clear-reward', methods=['POST'])
def clear_reward():
    data = request.json
    class_id = data.get('classId')
    minutes = data.get('minutes')
    
    if not class_id or minutes is None:
        return jsonify({'status': 'error', 'message': '参数不完整'})
    
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    # 记录核销历史
    history = load_history()
    history.append({
        'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'classId': class_id,
        'className': classes[class_id]['name'],
        'type': 'reward_clearance',
        'minutes': minutes
    })
    save_history(history)
    
    return jsonify({'status': 'success'})

# 核销惩罚
@app.route('/api/clear-penalty', methods=['POST'])
def clear_penalty():
    data = request.json
    class_id = data.get('classId')
    level = data.get('level')
    
    if not class_id or level is None:
        return jsonify({'status': 'error', 'message': '参数不完整'})
    
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    # 记录核销历史
    history = load_history()
    history.append({
        'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'classId': class_id,
        'className': classes[class_id]['name'],
        'type': 'penalty_clearance',
        'level': level
    })
    save_history(history)
    
    return jsonify({'status': 'success'})

# 重置班级分数（核销所有奖励和惩罚）
@app.route('/api/reset-class', methods=['POST'])
def reset_class():
    data = request.json
    class_id = data.get('classId')
    
    if not class_id:
        return jsonify({'status': 'error', 'message': '参数不完整'})
    
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    # 获取初始分数（默认为40）
    initial_score = classes[class_id].get('initial_score', 40)
    
    # 重置分数
    classes[class_id]['score'] = initial_score
    
    # 记录重置历史
    history = load_history()
    history.append({
        'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'classId': class_id,
        'className': classes[class_id]['name'],
        'type': 'class_reset',
        'old_score': classes[class_id]['score'],
        'new_score': initial_score
    })
    
    save_classes(classes)
    save_history(history)
    
    return jsonify({'status': 'success'})

# API路由 - 导入数据
@app.route('/api/import', methods=['POST'])
def import_data():
    if 'file' not in request.files:
        return jsonify({'status': 'error', 'message': '没有文件上传'})
    
    file = request.files['file']
    if file.filename == '':
        return jsonify({'status': 'error', 'message': '没有选择文件'})
    
    if not file.filename.endswith('.json'):
        return jsonify({'status': 'error', 'message': '只支持JSON文件'})
    
    try:
        data = json.load(file)
        
        # 验证数据格式
        if 'classData' not in data or 'freezeThreshold' not in data:
            return jsonify({'status': 'error', 'message': '文件格式不正确'})
        
        # 备份当前数据
        backup_time = datetime.now().strftime('%Y%m%d_%H%M%S')
        classes_backup = load_classes()
        history_backup = load_history()
        
        # 保存备份
        backup_data = {
            'classData': classes_backup,
            'freezeThreshold': 30,
            'recentHistory': history_backup,
            'backupTime': backup_time
        }
        
        backup_filename = f"backup_{backup_time}.json"
        backup_path = os.path.join(DATA_DIR, backup_filename)
        
        with open(backup_path, 'w', encoding='utf-8') as f:
            json.dump(backup_data, f, ensure_ascii=False, indent=2)
        
        # 应用导入的数据
        save_classes(data['classData'])
        save_history(data.get('recentHistory', []))
        
        return jsonify({'status': 'success', 'message': f'数据导入成功，原数据已备份为{backup_filename}'})
    
    except Exception as e:
        return jsonify({'status': 'error', 'message': f'文件解析失败: {str(e)}'})

# 获取班级的奖励和惩罚状态
@app.route('/api/class-status/<class_id>', methods=['GET'])
def get_class_status(class_id):
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    class_info = classes[class_id]
    score = class_info['score']
    
    # 计算奖励状态
    reward_minutes = 0
    if score >= 90:
        reward_minutes = 15
    elif score >= 80:
        reward_minutes = 10
    elif score >= 70:
        reward_minutes = 8
    elif score >= 60:
        reward_minutes = 5
    
    # 计算惩罚状态
    penalty_sessions = 0
    penalty_type = "无惩罚"
    if score < 10:
        penalty_sessions = 3
        penalty_type = "暂停3节课+德育处备案"
    elif score < 20:
        penalty_sessions = 2
        penalty_type = "暂停2节课+家长沟通"
    elif score < 30:
        penalty_sessions = 1
        penalty_type = "暂停1节课+书面反思"
    elif score < 40:
        penalty_sessions = 0  # 只需通知班主任，不需要核销
        penalty_type = "警告通知班主任"
    
    # 获取已核销的记录
    reward_used = class_info.get('reward_used', 0)
    penalty_used = class_info.get('penalty_used', 0)
    
    return jsonify({
        'status': 'success',
        'reward': {
            'total': reward_minutes,
            'used': reward_used,
            'remaining': max(0, reward_minutes - reward_used)
        },
        'penalty': {
            'total': penalty_sessions,
            'used': penalty_used,
            'remaining': max(0, penalty_sessions - penalty_used),
            'type': penalty_type
        },
        'initial_score': class_info.get('initial_score', 40)
    })

# 核销奖励时间
@app.route('/api/use-reward', methods=['POST'])
def use_reward():
    data = request.json
    class_id = data.get('classId')
    minutes = data.get('minutes', 1)
    
    if not class_id or minutes <= 0:
        return jsonify({'status': 'error', 'message': '参数错误'})
    
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    class_info = classes[class_id]
    score = class_info['score']
    
    # 计算总奖励时间
    reward_minutes = 0
    if score >= 90:
        reward_minutes = 15
    elif score >= 80:
        reward_minutes = 10
    elif score >= 70:
        reward_minutes = 8
    elif score >= 60:
        reward_minutes = 5
    
    # 如果没有奖励时间，直接返回错误
    if reward_minutes == 0:
        return jsonify({'status': 'error', 'message': '当前分数区间无自由探索时间'})
    
    # 获取已使用的奖励时间
    reward_used = class_info.get('reward_used', 0)
    remaining = reward_minutes - reward_used
    
    if minutes > remaining:
        return jsonify({'status': 'error', 'message': f'剩余奖励时间不足，只有{remaining}分钟'})
    
    # 更新已使用的奖励时间
    class_info['reward_used'] = reward_used + minutes
    
    # 检查是否需要重置分数
    if class_info['reward_used'] >= reward_minutes and reward_minutes > 0:
        # 重置分数到初始值
        initial_score = class_info.get('initial_score', 40)
        class_info['score'] = initial_score
        class_info['reward_used'] = 0
        class_info['penalty_used'] = 0
        
        # 记录重置历史
        history = load_history()
        history.append({
            'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'classId': class_id,
            'className': class_info['name'],
            'type': 'reward_complete_reset',
            'message': f'奖励已全部使用，分数重置为{initial_score}分'
        })
        save_history(history)
    
    save_classes(classes)
    
    # 记录使用历史
    history = load_history()
    history.append({
        'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'classId': class_id,
        'className': class_info['name'],
        'type': 'reward_used',
        'minutes': minutes,
        'remaining': max(0, reward_minutes - class_info['reward_used'])
    })
    save_history(history)
    
    return jsonify({
        'status': 'success', 
        'remaining': max(0, reward_minutes - minutes),
        'message': f'成功使用{minutes}分钟自由探索时间'
    })
# 核销惩罚
@app.route('/api/use-penalty', methods=['POST'])
def use_penalty():
    data = request.json
    class_id = data.get('classId')
    sessions = data.get('sessions', 1)
    
    if not class_id or sessions <= 0:
        return jsonify({'status': 'error', 'message': '参数错误'})
    
    classes = load_classes()
    
    if class_id not in classes:
        return jsonify({'status': 'error', 'message': '班级不存在'})
    
    class_info = classes[class_id]
    score = class_info['score']
    
    # 计算总惩罚节数
    penalty_sessions = 0
    if score < 10:
        penalty_sessions = 3
    elif score < 20:
        penalty_sessions = 2
    elif score < 30:
        penalty_sessions = 1
    
    # 获取已使用的惩罚节数
    penalty_used = class_info.get('penalty_used', 0)
    remaining = penalty_sessions - penalty_used
    
    if sessions > remaining:
        return jsonify({'status': 'error', 'message': f'剩余待执行惩罚不足，只有{remaining}节'})
    
    # 更新已使用的惩罚节数
    class_info['penalty_used'] = penalty_used + sessions
    
    # 检查是否需要重置分数
    if class_info['penalty_used'] >= penalty_sessions and penalty_sessions > 0:
        # 重置分数到初始值
        initial_score = class_info.get('initial_score', 40)
        class_info['score'] = initial_score
        class_info['reward_used'] = 0
        class_info['penalty_used'] = 0
        
        # 记录重置历史
        history = load_history()
        history.append({
            'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'classId': class_id,
            'className': class_info['name'],
            'type': 'penalty_complete_reset',
            'message': f'惩罚已全部执行，分数重置为{initial_score}分'
        })
        save_history(history)
    
    save_classes(classes)
    
    # 记录使用历史
    history = load_history()
    history.append({
        'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        'classId': class_id,
        'className': class_info['name'],
        'type': 'penalty_used',
        'sessions': sessions,
        'remaining': max(0, penalty_sessions - class_info['penalty_used'])
    })
    save_history(history)
    
    return jsonify({'status': 'success', 'remaining': max(0, penalty_sessions - class_info['penalty_used'])})




if __name__ == '__main__':
    init_data_files()
    app.run(host='0.0.0.0', port=9898, debug=False)